package net.entelijan.cobean.notification;

import static org.junit.Assert.assertEquals;

import java.beans.PropertyChangeListener;
import java.util.List;

import net.entelijan.cobean.combobox.DefaultComboBoxInitializer;
import net.entelijan.cobean.core.ISingleSelectionListCobean;
import net.entelijan.cobean.core.impl.INamedPropertyChangeListener;
import net.entelijan.cobean.core.impl.IPropertyChangeListenerAware;
import net.entelijan.cobean.util.CobeanUtil;
import net.entelijan.testutil.CobeanTestUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.fest.swing.fixture.FrameFixture;
import org.fest.swing.fixture.JComboBoxFixture;
import org.junit.Test;

public class ComboBoxNotificationFestTestCase {

	private static Log log = LogFactory
			.getLog(ComboBoxNotificationFestTestCase.class);

	public void dummy() {
		// Created to let testcases succeed even if all tests are disabled
	}
	
    @Test
	public void test() {
		ComboBoxNotificationTestFrame frame = new ComboBoxNotificationTestFrame(
				"TF");
		FrameFixture frameFix = new FrameFixture(frame);
		try {
			frameFix.show();
			JComboBoxFixture comboBoxFix = frameFix.comboBox("comboBox");

			final RecordingPropertyChangeListener listener = new RecordingPropertyChangeListener("value");
			final RecordingPropertyChangeListener selectedValueConsumer = new RecordingPropertyChangeListener("selectedValue");
			ISingleSelectionListCobean<String> cobean = init(frame,
					listener, selectedValueConsumer);
			List<String> value = CobeanTestUtil
					.createStringList("Der Assistent der Zauberer");
			cobean.setValue(value);
			assertEquals(1, listener.getNotificationCount());
			assertEquals(0, selectedValueConsumer.getNotificationCount());
			assertEventContentBean(null, CobeanTestUtil
					.createStringList("Der Assistent der Zauberer"), "value",
					listener.getEventContents().get(0));
			
			comboBoxFix.selectItem(3);
			pause();
			assertEquals(1, listener.getNotificationCount());
			assertEquals(1, selectedValueConsumer.getNotificationCount());
			assertEventContentBean(null, "Zauberer", "selectedValue",
					selectedValueConsumer.getEventContents().get(0));
			
			comboBoxFix.selectItem(2);
			pause();
			assertEquals(1, listener.getNotificationCount());
			assertEquals(2, selectedValueConsumer.getNotificationCount());
			assertEventContentBean("Zauberer", "der", "selectedValue",
					selectedValueConsumer.getEventContents().get(1));
			
			comboBoxFix.selectItem(2);
			pause();
			assertEquals(1, listener.getNotificationCount());
			assertEquals(2, selectedValueConsumer.getNotificationCount());
			assertEventContentBean("Zauberer", "der", "selectedValue",
					selectedValueConsumer.getEventContents().get(1));
			
			cobean.setSelectedValue("der");
			pause();
			comboBoxFix.requireSelection("der");
			assertEquals(1, listener.getNotificationCount());
			assertEquals(2, selectedValueConsumer.getNotificationCount());
			assertEventContentBean("Zauberer", "der", "selectedValue",
					selectedValueConsumer.getEventContents().get(1));
			
			cobean.setSelectedValue("Assistent");
			pause();
			comboBoxFix.requireSelection("Assistent");
			assertEquals(1, listener.getNotificationCount());
			assertEquals(3, selectedValueConsumer.getNotificationCount());
			assertEventContentBean("der", "Assistent", "selectedValue",
					selectedValueConsumer.getEventContents().get(2));
			
			cobean.setSelectedValue(null);
			pause();
			comboBoxFix.requireNoSelection();
			assertEquals(1, listener.getNotificationCount());
			assertEquals(4, selectedValueConsumer.getNotificationCount());
			assertEventContentBean("Assistent", null, "selectedValue",
					selectedValueConsumer.getEventContents().get(3));
			
		} finally {
			frameFix.cleanUp();
		}

	}

	private <T> void assertEventContentBean(Object oldValue, Object newValue,
			String propertyName, EventContentBean eventContentBean) {
		assertEquals(oldValue, eventContentBean.getOldValue());
		assertEquals(newValue, eventContentBean.getNewValue());
		assertEquals(propertyName, eventContentBean.getPropertyName());

	}

	private synchronized void pause() {
		try {
			this.wait(100);
		} catch (InterruptedException e) {
			// Can be ignored
		}
	}

	private ISingleSelectionListCobean<String> init(
			ComboBoxNotificationTestFrame frame, INamedPropertyChangeListener... nb) {
		final DefaultComboBoxInitializer<String> ini = new DefaultComboBoxInitializer<String>();
		ini.setCoComboBox(frame.getComboBox());
		ISingleSelectionListCobean<String> cobean = ini.initialize();
		log.debug("Created cobean: " + cobean);
		if (cobean instanceof IPropertyChangeListenerAware) {
			log.debug(cobean + " is IPropertyChangeListenerAware");
			for (INamedPropertyChangeListener l : nb) {
				((IPropertyChangeListenerAware) cobean)
						.setPropertyChangeListener(l);
			}
		} else {
			log.debug(cobean + " is NOT IPropertyChangeListenerAware");
			for (PropertyChangeListener l : nb) {
				CobeanUtil.addPropertyChangeListenerUsingReflection(cobean, l);
			}
		}
		return cobean;
	}

}
